package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.ColorSign;
import com.myk.game.gobangchess.signs.TextSign;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 堵路狙击
 */
public class BlockRoadFightingRoom extends Room {

    //黑方狙击手位置
    private Point blackPoint;
    //白方狙击手位置
    private Point whitePoint;
    //最近的移动路径
    private List<Integer> movePathPoints;
    //最近落墙点
    private Integer fallWallPoint;
    //本回合是否移动过
    private boolean hasMoved;

    public BlockRoadFightingRoom(String roomName) {
        super(roomName, "\t\t夏日设计的新棋，放置障碍，步步进逼，将对方逼死！", "堵路狙击", GridsUtils.createEmptyGrids(10, 10), true, true);
        curGrids[4][4] = 1;
        curGrids[5][5] = 2;
        blackPoint = new Point(4, 4);
        whitePoint = new Point(5, 5);
    }

    @Override
    public String getRuleText() {
        return "《堵路狙击规则》\n" +
                "开局场上黑白双方各有一个狙击手。\n" +
                "黑先白后轮流移动，直走1格可走任意次。\n" +
                "移动后在场上任意位置放置一堵墙。\n" +
                "轮到你移动时，对方狙击手会向四个方向进行瞄准。\n" +
                "瞄准不会穿过墙，移动不能走到对方瞄准线上。\n" +
                "无法移动就算输了。";
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        curGrids[4][4] = 1;
        curGrids[5][5] = 2;
        blackPoint = new Point(4, 4);
        whitePoint = new Point(5, 5);
        movePathPoints = null;
        fallWallPoint = null;
        hasMoved = false;
    }

    @Override
    public String getGameInfo() {
        //先清空棋盘
        signList.clear();
        //绘制移动路径
        if (movePathPoints != null) {
            for (int i = 0; i < movePathPoints.size() - 1; i++) {
                signList.add(new TextSign(movePathPoints.get(i), "👣", ColorCost.NEW_PUT_POINT_LIGHT));
            }
        }
        //绘制落墙点
        if (fallWallPoint != null) {
            //signList.add(new GroundSign(fallWallPoint, ColorCost.TRANSPARENT, ColorCost.NEW_PUT_POINT_LIGHT, 1.0f));
            signList.add(new TextSign(fallWallPoint, "○", ColorCost.NEW_PUT_POINT));
        }
        //绘制狙击手
        signList.add(new TextSign(getIndex(blackPoint.y, blackPoint.x), "💂", ColorCost.BLACK));
        signList.add(new TextSign(getIndex(whitePoint.y, whitePoint.x), "💂", ColorCost.WHITE));
        //绘制行动提示
        if (hasMoved) {
            gameTip = "请放置一堵墙";
            for (int i = 0; i < curGrids.length; i++) {
                for (int j = 0; j < curGrids[i].length; j++) {
                    if (curGrids[i][j] == 0) {
                        signList.add(new TextSign(getIndex(i, j), "·", ColorCost.NEW_PUT_POINT_LIGHT));
                        //signList.add(new ColorSign(getIndex(i, j), ColorCost.GOLDEN_WIN));
                    }
                }
            }
        }
        else {
            if (cur == 1 || cur == 2) {
                gameTip = "请选择可移动到的位置";
                //绘制可移动点
                List<Point> canMovePoints = findCanMovePoints(cur == 1 ? blackPoint : whitePoint);
                for (Point p : canMovePoints) {
                    //signList.add(new TextSign(getIndex(p.y, p.x), "👣", ColorCost.NEW_PUT_POINT));
                    signList.add(new ColorSign(getIndex(p.y, p.x), ColorCost.NEW_PUT_POINT_LIGHT));
                }
                //绘制狙击点
                List<Point> snipePoints = findSnipePoints(cur == 1 ? whitePoint : blackPoint);
                for (Point p : snipePoints) {
                    //signList.add(new TextSign(getIndex(p.y, p.x), "❌", ColorCost.NEW_FLIP_POINT));
                    signList.add(new ColorSign(getIndex(p.y, p.x), ColorCost.RED_TEXT_TRANSLUCENT));
                }
            }
            else {
                gameTip = "-1";
            }
        }

        return super.getGameInfo();
    }

    //寻找狙击点
    private List<Point> findSnipePoints(Point sniper) {
        List<Point> snipePoints = new ArrayList<>();

        // 向上狙击
        for (int row = sniper.y - 1; row >= 0; row--) {
            if (curGrids[row][sniper.x] == 9) { // 遇到墙，停止
                break;
            }
            snipePoints.add(new Point(sniper.x, row));
        }

        // 向下狙击
        for (int row = sniper.y + 1; row < curGrids.length; row++) {
            if (curGrids[row][sniper.x] == 9) { // 遇到墙，停止
                break;
            }
            snipePoints.add(new Point(sniper.x, row));
        }

        // 向左狙击
        for (int col = sniper.x - 1; col >= 0; col--) {
            if (curGrids[sniper.y][col] == 9) { // 遇到墙，停止
                break;
            }
            snipePoints.add(new Point(col, sniper.y));
        }

        // 向右狙击
        for (int col = sniper.x + 1; col < curGrids[0].length; col++) {
            if (curGrids[sniper.y][col] == 9) { // 遇到墙，停止
                break;
            }
            snipePoints.add(new Point(col, sniper.y));
        }

        return snipePoints;
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (hasMoved && curGrids[row][col] == 0) {
            fallWall(row, col);
            checkGameOver();
        }
        else {
            if (checkCanMove(row, col, value)) {
                moveSniper(row, col, value);
                noticeAllRefreshGameInfo();
            }
        }
    }

    //放置墙
    private void fallWall(int row, int col) {
        curGrids[row][col] = 9;
        fallWallPoint = getIndex(row, col);
        hasMoved = false;
    }

    //移动狙击手
    private void moveSniper(int row, int col, int side) {
        // 获取当前狙击手
        Point sniper = cur == 1 ? blackPoint : whitePoint;

        // 先记录原位置，再更新棋盘
        int fromRow = sniper.y;
        int fromCol = sniper.x;

        // 更新狙击手位置
        sniper.y = row;
        sniper.x = col;

        // 更新棋盘状态
        curGrids[fromRow][fromCol] = 0; // 清空原位置
        curGrids[row][col] = side;   // 设置新位置

        // 用最短路径算法记录路径上的所有点，从原来位置到新位置
        movePathPoints = findShortestPath(fromRow, fromCol, row, col, side);

        // 切换行动标记
        hasMoved = true;
    }

    private List<Integer> findShortestPath(int fromRow, int fromCol, int toRow, int toCol, int side) {
        // 如果起点和终点相同，返回空路径
        if (fromRow == toRow && fromCol == toCol) {
            //System.out.println("findShortestPath: 起点和终点相同，返回空路径");
            return new ArrayList<>();
        }

        // 获取对方狙击射线
        Point enemySniper = (side == 1) ? whitePoint : blackPoint;
        List<Point> snipePoints = findSnipePoints(enemySniper);

        //System.out.println("findShortestPath: 从 (" + fromRow + "," + fromCol + ") 到 (" + toRow + "," + toCol + ")");
        //System.out.println("findShortestPath: 对方狙击手在 (" + enemySniper.y + "," + enemySniper.x + ")");
        //System.out.println("findShortestPath: 狙击点数量: " + snipePoints.size());

        // BFS队列，存储位置和路径
        java.util.Queue<int[]> queue = new java.util.LinkedList<>();
        boolean[][] visited = new boolean[curGrids.length][curGrids[0].length];

        // 起点入队
        queue.offer(new int[]{fromRow, fromCol});
        visited[fromRow][fromCol] = true;

        // 父节点记录，用于重构路径
        int[][][] parent = new int[curGrids.length][curGrids[0].length][2];
        for (int i = 0; i < curGrids.length; i++) {
            for (int j = 0; j < curGrids[0].length; j++) {
                parent[i][j][0] = -1;
                parent[i][j][1] = -1;
            }
        }

        // 四个方向：上、下、左、右
        int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

        // BFS搜索
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int currentRow = current[0];
            int currentCol = current[1];

            // 如果到达终点
            if (currentRow == toRow && currentCol == toCol) {
                // 重构路径
                List<Integer> path = new ArrayList<>();
                int row = toRow;
                int col = toCol;

                // 从终点回溯到起点
                while (row != fromRow || col != fromCol) {
                    path.add(0, getIndex(row, col));
                    int prevRow = parent[row][col][0];
                    int prevCol = parent[row][col][1];
                    row = prevRow;
                    col = prevCol;
                }

                //System.out.println("findShortestPath: 找到路径，长度: " + path.size());
                path.add(0, getIndex(fromRow, fromCol)); // 添加起点
                return path;
            }

            // 扩展四个方向的邻居
            for (int[] dir : directions) {
                int newRow = currentRow + dir[0];
                int newCol = currentCol + dir[1];

                // 检查边界
                if (newRow >= 0 && newRow < curGrids.length &&
                        newCol >= 0 && newCol < curGrids[0].length) {

                    // 检查是否已访问
                    if (!visited[newRow][newCol]) {
                        Point newPoint = new Point(newCol, newRow);

                        // 检查是否是墙
                        if (curGrids[newRow][newCol] == 9) {
                            continue;
                        }

                        // 检查是否在对方狙击射线上
                        boolean isOnSnipeLine = false;
                        isOnSnipeLine = snipePoints.contains(newPoint);

                        if (!isOnSnipeLine) {
                            visited[newRow][newCol] = true;
                            parent[newRow][newCol][0] = currentRow;
                            parent[newRow][newCol][1] = currentCol;
                            queue.offer(new int[]{newRow, newCol});
                        }
                    }
                }
            }
        }

        // 没有找到路径
        //System.out.println("findShortestPath: 未找到路径");
        return null;
    }

    //检查是否可移动到该位置
    private boolean checkCanMove(int row, int col, int side) {
        Point currentSniper = (side == 1) ? blackPoint : whitePoint;
        List<Point> canMovePoints = findCanMovePoints(currentSniper);
        if (canMovePoints.isEmpty()) {
            return false;
        }

        Point targetPoint = new Point(col, row);
        return canMovePoints.contains(targetPoint);
    }

    //找出可移动点
    private List<Point> findCanMovePoints(Point currentSniper) {
        List<Point> canMovePoints = new ArrayList<>();

        // 计算对方狙击手位置
        Point enemySniper = (curGrids[currentSniper.y][currentSniper.x] == 1) ? whitePoint : blackPoint;

        // 计算对方狙击手的狙击射线（四个方向）
        List<Point> snipePoints = findSnipePoints(enemySniper);

        //System.out.println("findCanMovePoints: 当前狙击手在 (" + currentSniper.y + "," + currentSniper.x + ")");
        //System.out.println("findCanMovePoints: 对方狙击手在 (" + enemySniper.y + "," + enemySniper.x + ")");
        //System.out.println("findCanMovePoints: 狙击点数量: " + snipePoints.size());

        // 使用BFS找出所有可达的空格点
        java.util.Queue<Point> queue = new java.util.LinkedList<>();
        boolean[][] visited = new boolean[curGrids.length][curGrids[0].length];

        // 从当前狙击手位置开始搜索
        queue.offer(currentSniper);
        visited[currentSniper.y][currentSniper.x] = true;

        // 四个方向：上、下、左、右
        int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

        while (!queue.isEmpty()) {
            Point current = queue.poll();

            // 扩展四个方向的邻居
            for (int[] dir : directions) {
                int newRow = current.y + dir[0];
                int newCol = current.x + dir[1];

                // 检查边界
                if (newRow >= 0 && newRow < curGrids.length && newCol >= 0 && newCol < curGrids[0].length) {
                    // 检查是否已访问
                    if (!visited[newRow][newCol]) {
                        Point newPoint = new Point(newCol, newRow);

                        // 检查是否是墙
                        if (curGrids[newRow][newCol] == 9) {
                            visited[newRow][newCol] = true; // 标记为已访问，但跳过
                            continue;
                        }

                        // 检查是否是空格（可移动）
                        if (curGrids[newRow][newCol] == 0) {
                            // 检查是否在对方狙击射线上
                            boolean isOnSnipeLine = false;
                            isOnSnipeLine = snipePoints.contains(newPoint);

                            // 如果不在狙击射线上，则可以移动
                            if (!isOnSnipeLine) {
                                canMovePoints.add(newPoint);
                                queue.offer(newPoint);
                                //System.out.println("findCanMovePoints: 找到可移动点 (" + newRow + "," + newCol + ")");
                            }
                        }

                        visited[newRow][newCol] = true;
                    }
                }
            }
        }

        //System.out.println("findCanMovePoints: 总共找到 " + canMovePoints.size() + " 个可移动点");
        return canMovePoints;
    }

    private void checkGameOver() {
        stepAdd();
        Point currentSniper = (cur == 1) ? blackPoint : whitePoint;
        List<Point> hasCanMovePoints = findCanMovePoints(currentSniper);
        Point otherSniper = (cur == 1) ? whitePoint : blackPoint;
        List<Point> otherCanMovePoints = findCanMovePoints(otherSniper);
        if (hasCanMovePoints.isEmpty()) {
            if (cur == 1) {
                doOver(WinMode.WHITE_WIN, "黑方已无可移动点，游戏结束");
            }
            else {
                doOver(WinMode.BLACK_WIN, "白方已无可移动点，游戏结束");
            }
        }
        else if (otherCanMovePoints.isEmpty()) {
            if (cur == 1) {
                doOver(WinMode.BLACK_WIN, "白方已无可移动点，游戏结束");
            }
            else {
                doOver(WinMode.WHITE_WIN, "黑方已无可移动点，游戏结束");
            }
        }
        else {
            if (cur == 1) {
                noticeWhiteMove();
            }
            else {
                noticeBlackMove();
            }
        }
    }


}
